﻿using System;
using System.Collections.Generic;

namespace Borg.Framework
{
    public class PlugCommand : ICommand
    {
        private readonly string[][] _arguments =
            new[]
                {
                    new[] { "ExtensionInfo", "Plug", "SlotInfo", "ExtensionTypeInfo", "PlugTypeInfo" },
                    new string[0], new[] { "in", "from" },
                    new[] { "ExtensionInfo", "SlotInfo", "ExtensionTypeInfo" }
                };

        public IEnumerable<string> GetArguments(string[] command, int pos)
        {
            string[] args = null;

            switch (pos)
            {
                case 0:
                case 2:
                case 3:
                    return _arguments[pos];

                case 1:
                case 4:
                    if (command.Length >= (pos + 1))
                    {
                        var arg = command[pos];

                        if (arg != null)
                        {
                            int i;

                            if (arg != "ExtensionInfo")
                            {
                                switch (arg)
                                {
                                    case "Plug":
                                        args = new string[Runtime.Repository.PlugInfos.Count];
                                        for (i = 0; i < args.Length; i++)
                                            args[i] = Runtime.Repository.PlugInfos[i].Name;
                                        return args;
                                    
                                    case "SlotInfo":
                                        args = new string[Runtime.Repository.SlotInfos.Count];
                                        for (i = 0; i < args.Length; i++)
                                            args[i] = Runtime.Repository.SlotInfos[i].Name;
                                        return args;
                                    
                                    case "ExtensionTypeInfo":
                                        args = new string[Runtime.Repository.ExtensionTypeInfos.Count];
                                        for (i = 0; i < args.Length; i++)
                                            args[i] = Runtime.Repository.ExtensionTypeInfos[i].Name;
                                        return args;
                                    
                                    case "PlugTypeInfo":
                                        args = new string[Runtime.Repository.PlugTypeInfos.Count];
                                        for (i = 0; i < args.Length; i++)
                                            args[i] = Runtime.Repository.PlugTypeInfos[i].Name;
                                        return args;
                                }
                            }
                            else
                            {
                                args = new string[Runtime.Repository.ExtensionInfos.Count];

                                for (i = 0; i < args.Length; i++)
                                    args[i] = Runtime.Repository.ExtensionInfos[i].Name;
                            }
                        }

                        return args;
                    }

                    return new string[0];
            }

            return null;
        }

        private string Plug(string[] command)
        {
            string plug;
            RepositoryElement[] elements;

            if (command.Length < 2)
                return "Too few arguments.";

            if (!RuntimeCommands.ContainsArgument(command[1], _arguments[0]))
                return string.Format("  Invalid argument \"{0}\".{1}",
                    command[1], RuntimeCommands.lf);

            if (command.Length < 3)
                return "Too few arguments.";

            var repository = RuntimeCommands.Find(command, 1, out plug);

            if (repository.Length == 0)
                return plug;

            switch (command[1])
            {
                case "ExtensionInfo":
                    var i = 0;

                    if (command.Length >= 4)
                        if (command[3].Equals("in", StringComparison.CurrentCultureIgnoreCase))
                            i = 1;
                        else if (command[3].Equals("from", StringComparison.CurrentCultureIgnoreCase))
                            i = 2;

                    if (command.Length > 4)
                    {
                        if (i == 0)
                            return string.Format("\"in\" expected.", new object[0]);

                        if (command.Length < 5)
                            return "Too few arguments.";

                        if (command[4] != "ExtensionInfo")
                        {
                            if (command[4] != "ExtensionTypeInfo")
                                return string.Format("\"ExtensionInfo\" argument expected.", new object[0]);

                            if (command.Length < 6)
                                return "Too few arguments.";

                            elements = RuntimeCommands.Find(command, 4, out plug);

                            foreach (ExtensionInfo ei in repository)
                                foreach (ExtensionTypeInfo eti in elements)
                                    ei.PlugInSlots(eti);
                        }
                        else
                        {
                            if (command.Length < 6)
                                return "Too few arguments.";

                            elements = RuntimeCommands.Find(command, 4, out plug);

                            foreach (ExtensionInfo ei in repository)
                                foreach (ExtensionInfo item in elements)
                                    switch (i)
                                    {
                                        case 1:
                                            ei.PlugPlugs(item);
                                            break;

                                        case 2:
                                            ei.PlugInSlots(item);
                                            break;
                                    }
                        }
                    }
                    else
                    {
                        foreach (ExtensionInfo ei in repository)
                            if (i <= 1)
                                ei.PlugPlugs();
                            else if (i == 2)
                                ei.PlugInSlots();
                    }
                    break;
                
                case "Plug":
                    if (command.Length < 4)
                        foreach (PlugInfo pi in repository)
                            pi.Plug();
                    else
                    {
                        if (!command[3].Equals("in", StringComparison.CurrentCultureIgnoreCase))
                            return "\"in\" expected.";

                        if (command.Length < 5)
                            return "  Too few arguments.";

                        if (command[4] != "SlotInfo")
                            return "\"SlotInfo\" argument expected.";

                        if (command.Length < 6)
                            return "  Too few arguments.";

                        elements = RuntimeCommands.Find(command, 4, out plug);

                        foreach (PlugInfo pi in repository)
                            foreach (SlotInfo si in elements)
                                pi.Plug(si);
                    }
                    break;

                case "SlotInfo":
                    if (command.Length < 4)
                        foreach (SlotInfo si in repository)
                            si.Plug();
                    else
                    {
                        if (!command[3].Equals("in", StringComparison.CurrentCultureIgnoreCase))
                            return string.Format("  \"in\" expected.{0}", RuntimeCommands.lf);

                        if (command.Length < 5)
                            return "Too few arguments.";

                        if (command[4] != "Plug")
                            return string.Format("  \"Plug\" argument expected.{0}", RuntimeCommands.lf);

                        if (command.Length < 6)
                            return "Too few arguments.";

                        elements = RuntimeCommands.Find(command, 4, out plug);

                        foreach (SlotInfo si in repository)
                            foreach (PlugInfo pi in elements)
                                si.Plug(pi);
                    }
                    break;

                case "ExtensionTypeInfo":
                    if (command.Length < 6)
                        return "Too few arguments.";

                    if (!command[3].Equals("in", StringComparison.CurrentCultureIgnoreCase))
                        return string.Format("  \"in\" expected.{0}", RuntimeCommands.lf);

                    if (command[4] != "ExtensionInfo")
                        return string.Format("  \"ExtensionInfo\" argument expected.{0}", RuntimeCommands.lf);

                    elements = RuntimeCommands.Find(command, 4, out plug);

                    foreach (ExtensionTypeInfo eti in repository)
                        foreach (ExtensionInfo ei in elements)
                            eti.Plug(ei);

                    break;

                case "PlugTypeInfo":
                    if (command.Length < 6)
                        return "Too few arguments.";

                    if (!command[3].Equals("in", StringComparison.CurrentCultureIgnoreCase))
                        return string.Format("  \"in\" expected.{0}", RuntimeCommands.lf);

                    if (command[4] != "SlotInfo")
                        return string.Format("  \"SlotInfo\" argument expected.{0}", RuntimeCommands.lf);

                    elements = RuntimeCommands.Find(command, 4, out plug);

                    foreach (PlugTypeInfo pti in repository)
                        foreach (SlotInfo si in elements)
                            pti.Plug(si);
                    break;
            }

            return string.Empty;
        }

        public CommandHandler Handler
        {
            get { return Plug; }
        }

        public string Help
        {
            get { return "  Help for command \"plug\""; }
        }

        public string Name
        {
            get { return "plug"; }
        }
    }
}

